package cn.net.xyan.easy.gwt.rebind;



import cn.net.xyan.easy.gwt.client.ObjectFactory;
import cn.net.xyan.easy.gwt.shared.annotation.DynamicGWTObject;
import cn.net.xyan.easy.gwt.shared.annotation.RemoteService;
import com.google.gwt.core.ext.*;
import com.google.gwt.core.ext.typeinfo.JClassType;
import com.google.gwt.core.ext.typeinfo.TypeOracle;
import com.google.gwt.user.rebind.ClassSourceFileComposerFactory;
import com.google.gwt.user.rebind.SourceWriter;

import java.io.PrintWriter;
import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.List;

/**
 * Created by zarra on 16/2/16.
 */
public class   GWTServiceGenerator extends Generator
{
    static final String genPackageName = "cn.net.xyan.easy.gwt.generated";
    static final String genClassName = "ObjectFactoryImpl";

    TypeOracle typeOracle ;

    @Override
    public String generate( TreeLogger logger, GeneratorContext context, String typeName ) throws UnableToCompleteException
    {
        TypeOracle oracle = context.getTypeOracle( );

        typeOracle = oracle;

       // JClassType instantiableType = oracle.findType( GWTService.class.getName( ) );

        Class<? extends Annotation> annotation = DynamicGWTObject.class;

        List<JClassType> clazzes = new ArrayList<JClassType>( );

        PropertyOracle propertyOracle = context.getPropertyOracle( );

        for ( JClassType classType : oracle.getTypes( ) )
        {
            if (classType.findAnnotationInTypeHierarchy(annotation)!= null){
                clazzes.add( classType );
            }
        }

        ClassSourceFileComposerFactory composer = new ClassSourceFileComposerFactory( genPackageName, genClassName );
        composer.addImplementedInterface( ObjectFactory.class.getCanonicalName( ) );

        composer.addImport("com.google.gwt.core.client.*");

        composer.addImport("com.google.gwt.user.client.rpc.*");

        composer.addImport("cn.net.xyan.easy.gwt.client.*");

        for (JClassType cls : clazzes){
            composer.addImport( cls.getQualifiedSourceName());
        }
        //composer.addImport( "com.package.client.*" );

        PrintWriter printWriter = context.tryCreate( logger, genPackageName, genClassName );

        if ( printWriter != null )
        {
            SourceWriter sourceWriter = composer.createSourceWriter( context, printWriter );
            sourceWriter.println( String.format("public %s (){}",genClassName) );
            //sourceWriter.println( "}" );

            printFactoryMethod( clazzes, sourceWriter );

            sourceWriter.commit( logger );
        }
        return composer.getCreatedClassName( );
    }

    private void printFactoryMethod( List<JClassType> clazzes, SourceWriter sourceWriter )
    {
        sourceWriter.println( );

        sourceWriter.println( "public <T, V> T newInstance( Class<V> clazz ){return newInstance(clazz.getName());}");


        sourceWriter.println( "public <T> T newInstance( String className) {" );

        for ( JClassType classType : clazzes )
        {
            //if ( classType.isAbstract( ) )
              //  continue;
            sourceWriter.println( );
            sourceWriter.indent( );
            sourceWriter.println(String.format("if(\"%s\".equals(className)){",classType.getQualifiedSourceName()));
            //sourceWriter.println( "if (clazz.getName().endsWith(\"." + classType.getName( ) + "\")) {" );
            sourceWriter.indent( );
           // sourceWriter.println( "return (T) new " + classType.getQualifiedSourceName( ) + "( );" );

            RemoteService remoteServiceConfig = classType.findAnnotationInTypeHierarchy(RemoteService.class);

            if (remoteServiceConfig == null) {
                sourceWriter.println(String.format("return (T)GWT.create(%s.class);", classType.getQualifiedSourceName()));
                sourceWriter.outdent();

            }else if (classType.isAssignableTo(typeOracle.findType("com.google.gwt.user.client.rpc.RemoteService"))){
                sourceWriter.println(String.format("T t =  (T)GWT.create(%s.class);", classType.getQualifiedSourceName()));
                sourceWriter.println(String.format("ServiceDefTarget endpoint=(ServiceDefTarget)t;\n" +
                        "String moduleRelativeURL=EZGwt.appRoot()+ \"/gwt\"+ \"%s\";\n" +
                        "endpoint.setServiceEntryPoint(moduleRelativeURL);\n" +
                        "endpoint.setRpcRequestBuilder(EZGwt.createRpcRequestBuilder());\n" +
                        "return t;", remoteServiceConfig.value()));
                sourceWriter.outdent( );
            }
            sourceWriter.println("}");
            sourceWriter.outdent( );
            sourceWriter.println( );
        }

        sourceWriter.indent();
        sourceWriter.println("return (T) null;");
        sourceWriter.outdent();
        sourceWriter.println();
        sourceWriter.println("}");
        sourceWriter.outdent( );
        sourceWriter.println( );
    }
}